﻿namespace Home.Test.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Mvc;
    using Home.Test.Models;
    using Home.Test.Repository;
    using QQNamespace = Home.Test.QQ;
    using SinaNamespace = Home.Test.Sina;
    using WeiXinNamespace = Home.Test.WeiXin;

    public class HomeController : Controller
    {
        [HttpGet]
        public ActionResult Index()
        {
            return View();
        }

        [HttpGet]
        public ActionResult Login(string param)
        {
            var type = GetIdentityProviderSource();
            switch (type)
            {
                case IdentityProviderSource.QQ:
                    {
                        this.ViewBag.IdentityProviderText = "腾讯 QQ";
                        break;
                    }
                case IdentityProviderSource.Sina:
                    {
                        this.ViewBag.IdentityProviderText = "新浪微博";
                        break;
                    }
                case IdentityProviderSource.WeiXin:
                    {
                        this.ViewBag.IdentityProviderText = "腾讯微信";
                        break;
                    }
                default:
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            return View(new LoginModel() { Parameter = param });
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginModel model)
        {
            if (!this.ModelState.IsValid)
            {
                return View(model);
            }

            using (var db = new IPDbContext())
            {
                var sns = db.Snses.FirstOrDefault(s => s.LoginName == model.LoginName);
                if (sns == null || sns.LoginPassword != model.Password)
                {
                    return View(model);
                }

                var redirectUrl = default(string);

                var type = GetIdentityProviderSource();
                switch (type)
                {
                    case IdentityProviderSource.QQ:
                        {
                            var param = Helper.Crypto.Unprotect<QQNamespace.AuthorizationQueryString>(model.Parameter);
                            var consent = await EnsureConsentAsync(db, sns.Id, param.ClientId, Helper.QQ.DefaultOpenId);
                            Helper.Authentication.SignIn(this.HttpContext, type, new QQNamespace.Cookie() { ConsentId = consent.Id });
                            redirectUrl = Helper.Web.ToUrl("qq/authorize", param);
                            break;
                        }
                    case IdentityProviderSource.Sina:
                        {
                            var param = Helper.Crypto.Unprotect<SinaNamespace.AuthorizationQueryString>(model.Parameter);
                            var consent = await EnsureConsentAsync(db, sns.Id, param.ClientId, Helper.Sina.DefaultOpenId);
                            Helper.Authentication.SignIn(this.HttpContext, type, new SinaNamespace.Cookie() { ConsentId = consent.Id });
                            redirectUrl = Helper.Web.ToUrl("sina/authorize", param);
                            break;
                        }
                    case IdentityProviderSource.WeiXin:
                        {
                            var param = Helper.Crypto.Unprotect<WeiXinNamespace.AuthorizationQueryString>(model.Parameter);
                            var consent = await EnsureConsentAsync(db, sns.Id, param.AppId, Helper.WeiXin.DefaultOpenId);
                            Helper.Authentication.SignIn(this.HttpContext, type, new WeiXinNamespace.Cookie() { ConsentId = consent.Id });
                            redirectUrl = Helper.Web.ToUrl("weixin/authorize", param) + "#wechat_redirect";
                            break;
                        }
                    default:
                        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }

                redirectUrl = Helper.Web.ToAbsolute(this.HttpContext, redirectUrl);
                return Redirect(redirectUrl);
            }
        }

        [HttpGet]
        public ActionResult Logout(string return_url)
        {
            var type = GetIdentityProviderSource();
            if (type == IdentityProviderSource.Unknown)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            Helper.Authentication.SignOff(this.HttpContext, type);

            return Redirect(return_url);
        }

        private IdentityProviderSource GetIdentityProviderSource()
        {
            if (this.Request.Url.Segments.Length == 2)
            {
                var action = this.Request.Url.Segments[1].ToLowerInvariant();
                if (action == "login" || action == "logout")
                {
                    var name = this.Request.Url.Segments[0].ToLowerInvariant();
                    switch (name)
                    {
                        case "qq": return IdentityProviderSource.QQ;
                        case "sina": return IdentityProviderSource.Sina;
                        case "weixin": return IdentityProviderSource.WeiXin;
                    }
                }
            }

            return IdentityProviderSource.Unknown;
        }

        private static async Task<IPConsent> EnsureConsentAsync(IPDbContext db, Guid snsId, string clientId, string openId)
        {
            var consent = await db.Consents.FirstOrDefaultAsync(c => c.SnsId == snsId && c.ClientId == clientId && c.OpenId == openId);

            if (consent == null)
            {
                consent = new IPConsent()
                {
                    Id = Guid.NewGuid(),
                    SnsId = snsId,
                    ClientId = clientId,
                    OpenId = openId,
                };
                db.Consents.Add(consent);
                await db.SaveChangesAsync();
            }

            return consent;
        }
    }
}